﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Media;
using OpenLS.Drawing;
using OpenLS.UI.Internals;

namespace OpenLS.Spreadsheet.UI.Internals
{
    class FillPainter
    {
        private readonly DrawingContext drawingContext;
        private readonly ColorScheme colorScheme;
        private readonly ColorMode mode;
        private LayoutRounder _layoutRounder;
        private Pen pen;

        public FillPainter(FrameworkElement element, DrawingContext drawingContext, ColorScheme colorScheme, ColorMode colorMode)
        {
            this.drawingContext = drawingContext;
            this.colorScheme = colorScheme;
            this.mode = colorMode;
            this._layoutRounder = new LayoutRounder(element);
        }

        private void DrawRectangle(Brush brush, Rect rect)
        {
            drawingContext.DrawRectangle(brush, null, rect);
        }
        public void DrawRectangle(Fill fill, Rect rect)
        {
            if (fill == null)
                return;
            if (mode == ColorMode.BlackAndWhite)
                return;
            if (fill is PatternFill)
            {
                PatternFill patternFill = (PatternFill)fill;
                if (patternFill.ForegroundColor == null && patternFill.BackgroundColor == null && patternFill.Type != PatternType.Solid) //\\ tocheck
                    return;
                switch (patternFill.Type)
                {
                    case PatternType.None:
                        return;
                    case PatternType.Solid:
                        DrawRectangle(getBrush(mode, fill, colorScheme), rect);
                        return;
                    default:
                        DrawPatternRectangle(patternFill, rect);
                        return;

                }
            }
            DrawRectangle(getBrush(mode, fill, colorScheme), rect);
        }

        private void DrawPatternRectangle(PatternFill patternFill, Rect rect)
        {
            Brush backgroundBrush = ColorToBrushConverter.GetBrush(patternFill.BackgroundColor, colorScheme) ?? Brushes.Transparent;
            if (patternFill.ForegroundColor == null)
            {
                drawingContext.DrawRectangle(backgroundBrush, null, rect);
                return;
            }
            Brush foregroundBrush = ColorToBrushConverter.GetBrush(patternFill.ForegroundColor, colorScheme);
            drawingContext.DrawRectangle(GetPatternBrush(patternFill.Type, foregroundBrush, backgroundBrush), null, _layoutRounder.RoundRect(rect));

        }

        private static IEnumerable<Rect> GetPatternRects (PatternType type)
        {
            switch (type)
            {
                case PatternType.None:
                case PatternType.Solid:
                    throw new NotSupportedException();
                case PatternType.MediumGray:
                   yield return  new Rect(0, 1, 1, 1);
                    yield return new Rect(1, 0, 1, 1);
                    break;
                case PatternType.DarkGray:
                    yield return new Rect(0, 0, 1, 4);
                    yield return new Rect(1, 1, 1, 1);
                    yield return new Rect(2, 0, 1, 4);
                    yield return new Rect(3, 3, 1, 1);
                    break;
                case PatternType.LightGray:
                    yield return new Rect(0, 0, 1, 1);
                    yield return new Rect(2, 1, 1, 1);
                    yield return new Rect(0, 2, 1, 1);
                    yield return new Rect(2, 3, 1, 1);
                    break;
                case PatternType.Gray125:
                    yield return new Rect(1, 1, 1, 1);
                    yield return new Rect(3, 3, 1, 1);
                    break;
                case PatternType.Gray0625:
                    yield return new Rect(1, 1, 1, 1);
                    yield return new Rect(5, 5, 1, 1);
                    break;
                    case PatternType.DarkTrellis:
                    yield return new Rect(0, 0, 4, 1);
                    yield return new Rect(0, 1, 2, 1);
                    yield return new Rect(0, 2, 4, 1);
                    yield return new Rect(2, 3, 2, 1);
                    break;
                    case PatternType.DarkGrid:
                    yield return new Rect(0, 0, 2, 2);
                    yield return new Rect(2, 2, 2, 2);
                    break;
                    case PatternType.DarkHorizontal:
                    yield return new Rect(0, 0, 4, 2);
                    break;
                    case PatternType.DarkVertical:
                    yield return new Rect(0, 0, 2, 4);
                    break;
                case PatternType.LightHorizontal:
                    yield return new Rect(0 ,0, 4, 1);
                    break;
                case PatternType.LightVertical:
                    yield return new Rect(0, 0, 1, 4);
                    break;
                case PatternType.LightGrid:
                    yield return new Rect(0, 0, 1, 4);
                    yield return new Rect(0, 0, 4, 1);
                    break;
                case PatternType.LightTrellis:
                    yield return new Rect(0, 0, 1, 1);
                    yield return new Rect(1, 1, 1, 1);
                    yield return new Rect(2, 2, 1, 1);
                    yield return new Rect(3, 3, 1, 1);
                    yield return new Rect(1, 3, 1, 1);
                    yield return new Rect(3, 1, 1, 1);
                    break;
                case PatternType.DarkDown:
                    yield return new Rect(0, 0, 2, 1);
                    yield return new Rect(1, 1, 2, 1);
                    yield return new Rect(2, 2, 2, 1);
                    yield return new Rect(3, 3, 1, 1);
                    yield return new Rect(0, 3, 1, 1);
                    break;
                case PatternType.DarkUp:
                    yield return new Rect(3, 0, 1, 1);
                    yield return new Rect(0, 0, 1, 1);
                    yield return new Rect(2, 1, 2, 1);
                    yield return new Rect(1, 2, 2, 1);
                    yield return new Rect(0, 3, 2, 1);
                    break;
                case PatternType.LightDown:
                                        yield return new Rect(0, 0, 1, 1);
                    yield return new Rect(1, 1, 1, 1);
                    yield return new Rect(2, 2, 1, 1);
                    yield return new Rect(3, 3, 1, 1);
                    break;

                case PatternType.LightUp:
                    yield return new Rect(3, 0, 1, 1);
                    yield return new Rect(2, 1, 1, 1);
                    yield return new Rect(1, 2, 1, 1);
                    yield return new Rect(0, 3, 1, 1);
                    break;

                default:
                    throw new NotSupportedException();
            }
        }
        static Brush GetPatternBrush (PatternType type, Brush foregroundBrush, Brush backgroundBrush)
        {
            if (foregroundBrush == null)
                return backgroundBrush;
            if (backgroundBrush == null)
                backgroundBrush = Brushes.Transparent;
            DrawingBrush result = new DrawingBrush();
            DrawingGroup group = new DrawingGroup();
            Size size = GetPatternSize(type);
#if DEBUG
            foreach (var rect in GetPatternRects(type))
            {
                Debug.Assert(rect.Right <= size.Width);
                Debug.Assert(rect.Bottom <= size.Height);
            }
#endif
            group.Children.Add(new GeometryDrawing(backgroundBrush, null, new RectangleGeometry (new Rect(new Point(), size))));
            foreach (var rect in GetPatternRects(type))
                group.Children.Add(new GeometryDrawing(foregroundBrush, null, new RectangleGeometry(rect)));
            result.Drawing = group;
            result.TileMode = TileMode.Tile;
            result.ViewportUnits = BrushMappingMode.Absolute;
            result.Viewport = new Rect(new Point(), size);
            return result;
        }
        public static Size GetPatternSize(PatternType type)
        {
            switch (type)
            {
                case PatternType.None:
                case PatternType.Solid:
                    throw new NotSupportedException();
                case PatternType.MediumGray:
                    return new Size(2, 2);
                case PatternType.Gray0625:
                    return new Size(8, 8);
                case PatternType.DarkDown:
                case PatternType.DarkGray:
                case PatternType.DarkGrid:
                case PatternType.DarkHorizontal:
                case PatternType.DarkTrellis:
                case PatternType.DarkUp:
                case PatternType.DarkVertical:
                case PatternType.Gray125:
                case PatternType.LightDown:
                case PatternType.LightGray:
                case PatternType.LightGrid:
                case PatternType.LightHorizontal:
                case PatternType.LightTrellis:
                case PatternType.LightUp:
                case PatternType.LightVertical:
                    return new Size(4, 4);

                default:
                    throw new NotSupportedException();

            }
        }

        private static Brush getBrush(ColorMode mode, Fill foreground, ColorScheme scheme)
        {
            switch (mode)
            {
                case ColorMode.BlackAndWhite:
                    return null;
                default:
                    return FillToBrushConverter.GetBrush(foreground, scheme);
            }
        }

    }
}